package com.heima.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.StringUtils;
import com.heima.common.dtos.ResponseResult;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.search.dto.UserSearchDto;
import com.heima.search.service.ArticleSearchService;
import com.heima.search.service.UserSearchService;
import com.heima.user.pojo.User;
import com.heima.utils.thread.AppUserThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private UserSearchService userSearchService;

    /**
     * es文章分页检索
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult search(UserSearchDto dto) throws IOException {

        String searchWords = dto.getSearchWords();
        //当前时间，下面查询条件就是查询小于minBehotTime，这样就会查询到全部内容
        Date minBehotTime = new Date();
        int pageSize = dto.getPageSize();
        int pageNum = dto.getPageNum();
        int fromIndex = dto.getFromIndex();

        log.info("fromIndex值为{}", fromIndex);

        //1.检查参数
        if (dto == null || StringUtils.isBlank(dto.getSearchWords())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //异步方法将搜索记录存进MongoDB中，userId从线程中取出
        User user = AppUserThreadLocalUtil.getUser();
        //System.out.println(user == null ? "user为空" : "user存在");
        //dto.getFromIndex()指当前分页为第一页，防止重复存储记录，因为分页就是getFromIndex参数不一样，就是只存一次
        if (user != null && dto.getFromIndex() == 0) {
            log.info("将搜索词{}存入MongoDB", searchWords);
            userSearchService.insert(searchWords, user.getId());
        }

        //2.设置查询条件
        SearchRequest searchRequest = new SearchRequest("lead_news");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //布尔查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //关键字的分词之后查询
        //QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(dto.getSearchWords()).field("title").field("content").defaultOperator(Operator.OR);
        //boolQueryBuilder.must(queryStringQueryBuilder);

        boolQueryBuilder.must(QueryBuilders.multiMatchQuery(searchWords, "title", "content"));

        //查询小于mindate的数据
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime").lt(minBehotTime.getTime());

        System.out.println("当前获取的前端传递时间" + minBehotTime);

        boolQueryBuilder.filter(rangeQueryBuilder);

        //分页查询
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(dto.getPageSize());

        //按照发布时间倒序查询
        searchSourceBuilder.sort("publishTime", SortOrder.DESC);

        //设置高亮  title
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.preTags("<font style='color: red; font-size: inherit;'>");
        highlightBuilder.postTags("</font>");
        searchSourceBuilder.highlighter(highlightBuilder);


        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);


        //3.结果封装返回

        List<HashMap> list = new ArrayList<>();

        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            String json = hit.getSourceAsString();
            //将结果集转为Map类型
            HashMap map = JSON.parseObject(json, HashMap.class);
            //处理高亮
            if (hit.getHighlightFields() != null && hit.getHighlightFields().size() > 0) {
                //Text[] titles = hit.getHighlightFields().get("title").getFragments();

                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField title1 = highlightFields.get("title");
                String hightlightValue = title1.getFragments()[0].string();

                //String title = StringUtils.join(titles, "");
                //高亮标题，前端通过"h_title"取出
                map.put("h_title", hightlightValue);
            } else {
                //原始标题
                map.put("h_title", map.get("title"));
            }
            list.add(map);
        }

        log.info("es搜索到的结果{}", list);

        return ResponseResult.okResult(list);

    }
}